import glob
import os
import socket
import json
import time
from datetime import datetime
import yaml
import pandas as pd
from util.load_port import load_port


class SensorClient:
    def __init__(self, host="127.0.0.1", port=8888):
        self.host = host
        self.port = port
        self.socket = None
        self.connected = False

    def connect(self):
        """连接 C++ 同步服务端"""
        try:
            self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.socket.connect((self.host, self.port))
            self.connected = True
            print(f"✅ 连接 C++ 服务端成功（{self.host}:{self.port}）")
        except Exception as e:
            print(f"❌ 连接失败：{str(e)}")
            self.connected = False

    def send_command(self, cmd, **kwargs):
        """发送指令并接收响应（同步阻塞）"""
        if not self.connected:
            return {"status": "error", "msg": "未连接服务端"}

        try:
            # 构造 JSON 指令（加换行符分隔）
            command = {"cmd": cmd, **kwargs}
            cmd_str = json.dumps(command) + "\n"
            self.socket.sendall(cmd_str.encode("utf-8"))
            print(f"📤 发送指令：{cmd_str.strip()}")

            # 接收响应（同步阻塞，直到收到换行符）
            response_data = b""
            while True:
                chunk = self.socket.recv(1024)
                if not chunk:
                    self.connected = False
                    return {"status": "error", "msg": "服务端断开连接"}
                response_data += chunk
                if b"\n" in response_data:
                    break  # 收到换行符，响应结束

            # 解析响应
            response_str = response_data.decode("utf-8").strip()
            print(f"📥 接收响应：{response_str}")
            response_json = json.loads(response_str)

            # 增加对 status: success 的判断和处理
            if response_json.get("status") == "success":
                print(f"✅ 指令执行成功：{response_json.get('msg', '无详细信息')}")
            else:
                # 非 success 状态（如 error），提取错误信息
                error_msg = response_json.get("msg", "未知错误")
                print(f"❌ 指令执行失败：{error_msg}")

            return response_json

        except json.JSONDecodeError:
            error_msg = f"响应格式错误，无法解析为JSON：{response_str}"
            print(f"❌ {error_msg}")
            return {"status": "error", "msg": error_msg}
        except Exception as e:
            error_msg = f"发送/接收指令异常：{str(e)}"
            print(f"❌ {error_msg}")
            return {"status": "error", "msg": error_msg}

    # 以下方法和之前完全一致
    def connect_sensors(self):
        return self.send_command("connect")

    def start_collection(self, interval_ms=100):
        return self.send_command("start", interval_ms=interval_ms)

    def stop_collection(self):
        return self.send_command("stop")

    def get_status(self):
        return self.send_command("status")

    def close(self):
        if self.socket:
            self.socket.close()
            self.connected = False
            print("🔌 断开与 C++ 服务端的连接")


    def playback_history_data(self, path):
        """
        读取指定路径下所有CSV文件并返回JSON格式数据
        :param path: 前端传入的文件夹路径
        :return: 包含所有CSV数据的JSON响应
        """
        try:
            # 1. 路径安全校验（防止路径遍历攻击）
            if not path or not isinstance(path, str):
                return {"status": "error", "msg": "无效的路径参数"}

            # 规范化路径（获取绝对路径，避免相对路径跳转）
            safe_path = os.path.abspath(path)
            if not os.path.exists(safe_path):
                return {"status": "error", "msg": f"路径不存在：{safe_path}"}
            if not os.path.isdir(safe_path):
                return {"status": "error", "msg": f"不是文件夹路径：{safe_path}"}

            # 2. 获取路径下所有CSV文件（包含子文件夹可选）
            # 仅当前文件夹：safe_path + "/*.csv"
            # 包含子文件夹：safe_path + "/**/*.csv", recursive=True
            csv_files = glob.glob(os.path.join(safe_path, "*.csv"), recursive=False)
            if not csv_files:
                return {"status": "warning", "msg": f"路径下无CSV文件：{safe_path}", "data": []}

            # 3. 批量读取CSV并转换为JSON
            result = []
            for file in csv_files:
                try:
                    # 读取CSV（根据实际格式调整参数，如分隔符、表头行等）
                    df = pd.read_csv(
                        file,
                        encoding="utf-8",
                        parse_dates=False,  # 日期解析根据实际CSV格式决定是否开启
                        low_memory=False  # 处理大型CSV时避免类型推断警告
                    )

                    # 转换为前端友好的格式（orient='records'生成列表字典）
                    file_data = {
                        "filename": os.path.basename(file),  # 仅保留文件名（不含路径）
                        "filepath": file,  # 完整路径（可选）
                        "file_size": os.path.getsize(file),  # 文件大小（字节）
                        "modify_time": datetime.fromtimestamp(os.path.getmtime(file)).strftime("%Y-%m-%d %H:%M:%S"),
                        "record_count": len(df),  # 记录条数
                        "data": df.to_dict(orient="records")  # 核心数据
                    }
                    result.append(file_data)
                    print(f"📂 成功读取CSV：{file}（{len(df)}条记录）")

                except Exception as e:
                    # 单个文件读取失败不影响整体，记录错误信息
                    result.append({
                        "filename": os.path.basename(file),
                        "status": "error",
                        "msg": f"文件读取失败：{str(e)}"
                    })
                    print(f"❌ 读取CSV失败 {file}：{str(e)}")

            # 4. 返回汇总结果
            return {
                "status": "success",
                "total_files": len(csv_files),
                "success_files": sum(1 for item in result if item.get("status") != "error"),
                "path": safe_path,
                "data": result
            }

        except Exception as e:
            return {"status": "error", "msg": f"回放历史数据失败：{str(e)}"}

    def select_all_same_timestamp(self, path, timestamp):
        ...

    def adjust_sampling_rate(self, target_rate):
        """
        调整采样率（适配C++接口：通过stop→start(新间隔)实现）
        :param target_rate: 目标采样率（单位：Hz，如10→10Hz=每100ms采集一次）
        :return: C++ 响应结果 + 调整信息
        """
        # 1. 基础校验：连接状态
        if not self.connected:
            return {
                "status": "error",
                "msg": "未连接C++服务器",
            }

        try:
            # 2. 采样率 → 采集间隔（ms）：C++ 只认 interval_ms，不认 rate
            # 公式：采样率(Hz) = 1000ms / 采集间隔(ms) → 间隔 = 1000 / 采样率
            if not isinstance(target_rate, (int, float)) or target_rate <= 0:
                return {
                    "status": "error",
                    "msg": f"无效采样率：{target_rate}（必须是正数，如10→10Hz）"
                }

            interval_ms = int(1000 / target_rate)
            # 校验间隔合法性（C++ 可能不处理0或负数，提前拦截）
            if interval_ms <= 0:
                return {
                    "status": "error",
                    "msg": f"采样率{target_rate}Hz过高（最大支持1000Hz，对应间隔1ms）"
                }

            # 3. 先查询当前采集状态（避免不必要的 stop 调用，可选但更严谨）
            status_result = self.get_status()
            if status_result.get("status") != "success":
                return {
                    "status": "error",
                    "msg": f"查询采集状态失败：{status_result.get('msg', '未知错误')}",
                    "cpp_response": status_result  # 携带C++原始响应，方便调试
                }

            # 4. 执行调整逻辑：仅当采集正在运行时，才需要 stop（C++ stop 无副作用，但减少无效调用）
            is_running = status_result.get("is_timer_running", False)
            stop_result = None
            if is_running:
                stop_result = self.stop_collection()
                if stop_result.get("status") != "success":
                    return {
                        "status": "error",
                        "msg": f"停止采集失败：{stop_result.get('msg', '未知错误')}",
                        "cpp_response": stop_result
                    }

            # 5. 用新间隔启动采集（C++ start 会覆盖原间隔，即使已在运行）
            start_result = self.start_collection(interval_ms=interval_ms)
            if start_result.get("status") != "success":
                return {
                    "status": "error",
                    "msg": f"启动新采集失败：{start_result.get('msg', '未知错误')}",
                    "cpp_response": start_result
                }

            # 6. 组装最终结果：包含 C++ 响应 + 调整信息（方便前端理解）
            final_result = {
                "status": "success",
                "msg": f"采样率调整完成（目标{target_rate}Hz → 实际{1000 / interval_ms}Hz）",
                "adjust_info": {
                    "target_rate": target_rate,  # 用户输入的目标采样率
                    "actual_interval_ms": interval_ms,  # 传给C++的实际间隔
                    "actual_rate": 1000 / interval_ms,  # 实际采样率（验证用）
                    "was_running": is_running  # 调整前是否在采集
                },
                "cpp_response": {
                    "stop": stop_result,  # C++ stop 响应（未调用则为None）
                    "start": start_result  # C++ start 响应
                },
            }
            return final_result

        except Exception as e:
            return {
                "status": "error",
                "msg": f"调整采样率异常：{str(e)}",
            }


    # 新增：获取当前连接的服务器信息（IP+端口+状态）
    # def get_current_server(self):
    #     """返回当前连接的C++服务器详情"""
    #     return {
    #         "host": self.current_host,
    #         "port": self.current_port,
    #         "connected": self.connected
    #     }

# 示例：控制流程
if __name__ == "__main__":
    config = load_port("./config/port.yaml")

    host = config.get("host", "127.0.0.1")
    port = config.get("port", 8888)

    client = SensorClient(host, port)
    client.connect()

    try:
        # 1. 连接传感器
        client.connect_sensors()
        # 2. 启动采集（200ms 间隔）
        client.start_collection(interval_ms=100)
        # 3. 运行 30 秒
        print("\n⏳ 采集运行中...（30秒后停止）")
        time.sleep(30)
        # 4. 停止采集
        client.stop_collection()
        # 5. 查询状态
        client.get_status()
    finally:
        client.close()